package com.sanyou.aspect;

import com.sanyou.aspect.annotation.LogRecord;
import com.sanyou.pojo.OperLog;
import com.sanyou.registry.IFunction;
import com.sanyou.registry.LogParseFunctionFactory;
import com.sanyou.service.OperLogService;
import com.sanyou.utils.SpELParserUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Optional;

/**
 * @Author yongxin
 * @Description 日志记录切面类
 */
@Aspect
@Component
public class OperLogAspect {

    @Autowired
    OperLogService operLogService;

    @Pointcut("@annotation(com.sanyou.aspect.annotation.LogRecord)")
    public void operPointCut() {}

    @Around("operPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        //获取class
        Class<?> clazz = joinPoint.getTarget().getClass();
        //获取访问的方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取方法所有参数及其类型
        Object[] args = joinPoint.getArgs();
        Class[] argClz = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        //获取访问的方法对象
        Method method = clazz.getDeclaredMethod(methodName, argClz);

        LogRecord annotation = method.getAnnotation(LogRecord.class);
        //执行方法
        Object result = joinPoint.proceed();

        //日志处理
        String productCode = SpELParserUtils.templateParse(annotation.productCode(), method, args);
        String content = "";
        // 判断是否指定了自定义函数
        if (StringUtils.isNotBlank(annotation.originalFunction())){
            //content = SpELParserUtils.functionParse(annotation.content());
            String productState = SpELParserUtils.templateParse("#{#productVo.getProductState()}", method, args);
            String maintainType = SpELParserUtils.templateParse("#{#productVo.getMaintainType()}", method, args);
            IFunction<Object> function = LogParseFunctionFactory.FUNCTION_MAP.get(annotation.originalFunction());
            content = (String) Optional.ofNullable(function)
                    .map(f -> f.apply(productState, maintainType))
                    .orElse(null);
        }else{
            content = SpELParserUtils.templateParse(annotation.content(), method, args);
        }
        int operType = annotation.operType();
        String operatorId = annotation.operatorId();
        Integer productState;
        if (StringUtils.isNotBlank(annotation.productState())){
            productState = Integer.valueOf(SpELParserUtils.templateParse(annotation.productState(), method, args));
        } else {
            productState = -1;
        }
        if (operType == 1){
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            operatorId = request.getHeader("userId");
        }
        OperLog operLog = OperLog.builder()
                .productCode(productCode)
                .operType(operType)
                .productState(productState)
                .content(content)
                .operatorId(operatorId)
                .logDate(new Date())
                .build();
        operLogService.insert(operLog);
        return result;
    }
}

